/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package myftp.core.controller;

import java.util.*;
import myftp.core.controller.plugin.*;
import myftp.core.model.AbstractModel;

/**
 *
 * @author CAVARLE Glenn, LUCAS Stéphane
 * Classe Singleton de contrôle global
 * Point d'entrée des requetes utilisateur
 * (possibilité gestion de filtres et plugins)
 */
public class FrontController {

    /**
     * instance du FrontController (Singleton)
     * @var instance
     */
    static private FrontController instance = null;
    /**
     * liste des plugins enregistrés
     * @var plugins
     */
    private ArrayList<PluginAbstract> plugins;
    /**
     * liste des "ActionController" déjà instanciés
     * @var controllers
     */
    private HashMap<String, ActionController> controllers;
    /**
     * listes des parametres à transmettre à l'Action
     * @var actionParams
     */
    private HashMap<String, Object> actionParams;
    /**
     * Action par defaut à exécuter
     * @var defaultAction
     */
    private String defaultAction = null;
    /**
     * Controller par defaut à exécuter
     * @var defaultController
     */
    private String defaultController = null;
    /**
     * Liste des parametres du Frontcontroller
     * @var params
     */
    private HashMap<String, Object> params;

    /**
     * Constructeur privé (Singleton)
     * Initilalisation des différents attributs
     */
    private FrontController() {
        this.plugins = new ArrayList();
        this.controllers = new HashMap();
        this.actionParams = new HashMap();
        this.params = new HashMap();
    }

    /**
     * Retourne l'instance du FrontController
     * @return FrontController
     */
    public static FrontController getInstance() {

        if (instance == null) {
            instance = new FrontController();
        }
        return instance;
    }

    /**
     * enregistrement d'un plugin
     * @param layoutPlugin
     */
    public void registerPlugin(PluginAbstract layoutPlugin) {
        this.plugins.add(layoutPlugin);
    }

    /**
     *Lancement de l'application
     * boucle d'initialisation des plugins
     * exécution du couple controller/action par défaut
     */
    public void run() {
        /*boucle d'exécution des plugins*/
        Iterator itr = this.plugins.iterator();
        while (itr.hasNext()) {
            PluginAbstract plugin = (PluginAbstract) itr.next();
            plugin.init();
        }
        /*dispatch du couple controller/action*/

        this.dispatch(defaultController, defaultAction);


    }

    /**
     * exécution d'une action avec le controller par défaut
     * @param actionName
     */
    public void dispatch(String actionName) {
        this.dispatch(actionName, "DefaultController");
    }

    /**
     * Exécution du couple controller/action
     * @param actionName
     * @param controllerName
     */
    public void dispatch(String actionName, String controllerName) {
        if (actionName != null) {
            try {
                ActionController controller = this.getController(controllerName);

                controller.setActionName(actionName);
                controller.setActionParams(this.getActionParams());
                controller.run();

            } catch (InstantiationException ex) {
                System.out.println(ex.getClass() + " : " + ex.getMessage());
            } catch (IllegalAccessException ex) {
                System.out.println(ex.getClass() + " : " + ex.getMessage());
            } catch (ClassNotFoundException ex) {
                System.out.println(ex.getClass() + " : " + ex.getMessage());

            }
        }
    }

    /**
     * getter d'un controller par son nom (reflexivité)
     * @param controllerName
     * @return
     * @throws ClassNotFoundException
     * @throws InstantiationException
     * @throws IllegalAccessException
     */
    private ActionController getController(String controllerName)
            throws ClassNotFoundException, InstantiationException, IllegalAccessException {
        ActionController controller;
        if (!this.controllers.containsKey(controllerName)) {

            controller = (ActionController) Class.forName("myftp.app.controller." + controllerName).newInstance();
            controller.setModel((AbstractModel) this.getParam("serverManager"));
            controller.setView(null);
            this.controllers.put(controllerName, controller);
        }
        return this.controllers.get(controllerName);

    }

    /**
     * setter des parmetres de l'action à exécuter
     * @param actionParams
     */
    public void setActionParams(HashMap<String, Object> actionParams) {
        this.actionParams = actionParams;
    }

    /**
     * setter d'un parametre de l'action à exécuter
     * @param key
     * @param actionParams
     */
    public void setActionParam(String key, Object actionParams) {
        this.actionParams.put(key, actionParams);
    }

    /**
     * getter des parmetres de l'action à exécuter
     * @return
     */
    public HashMap getActionParams() {
        return this.actionParams;
    }

    /**
     * getter d'un parametre de l'action à exécuter
     * @param key
     * @param actionParams
     */
    public Object getActionParam(String key) {
        if (!this.actionParams.containsKey(key)) {
            return null;
        }
        return this.actionParams.get(key);
    }

    public void setParams(HashMap<String, Object> params) {
        this.params = params;
    }

    public void setParam(String key, Object params) {
        this.params.put(key, params);
    }

    public HashMap getParams() {
        return this.params;
    }

    public Object getParam(String key) {
        if (!this.params.containsKey(key)) {
            return null;
        }
        return this.params.get(key);
    }
}
